﻿
using System.Configuration;
using FlexiCommerce.Components;
using FlexiCommerce.Configuration;
using FlexiCommerce.Persistence.NH;
using FlexiCommerce.Tests.Persistence;
using NUnit.Framework;
using System.Collections.Generic;
using FlexiCommerce.Details;
using FlexiCommerce.Persistence;
using System.Diagnostics;
using NUnit.Framework.SyntaxHelpers;
using FlexiCommerce.Engine;
using FlexiCommerce;
using Rhino.Mocks;
using FlexiCommerce.Tests.Persistence;
using FlexiCommerce.Tests.Persistence.Definitions;
using System;
using System.Reflection;
namespace FlexiCommerce.Tests.Persistence.NH {
    [TestFixture]
public class ItemRepositoryTests : DatabasePreparingBase
{
    NHRepository<int, GenericPersistenceItem> repository;
    ISessionProvider sessionProvider;

    [SetUp]
    public override void SetUp()
    {
        base.SetUp();
        CreateDatabaseSchema();

        sessionProvider = CreateSessionProvider();
        repository = new NHRepository<int, GenericPersistenceItem>(sessionProvider);
    }

    [Test]
    public void CanSave()
    {
        int itemID = SaveAnItem("savedItem", null);
        Assert.AreNotEqual(0, itemID);

        using (repository)
        {
            GenericPersistenceItem item = repository.Get(itemID);
            Assert.AreEqual(item.ID, itemID);
            repository.Delete(item);
            repository.Flush();
        }
    }

    [Test]
    public void CanUpdate()
    {
        int itemID = SaveAnItem("savedItem", null);

        using (repository)
        {
            GenericPersistenceItem item = repository.Get(itemID);
            item.Name = "updated item";
            repository.SaveOrUpdate(item);
            repository.Flush();
        }

        using (repository)
        {
            GenericPersistenceItem item = repository.Get(itemID);
            Assert.AreEqual("updated item", item.Name);
            repository.Delete(item);
            repository.Flush();
        }
    }

    [Test]
    public void CanFindAll()
    {
        int item1ID = SaveAnItem("first", null);
        int item2ID = SaveAnItem("second", null);
        int item3ID = SaveAnItem("third", null);

        using (repository)
        {
            ICollection<GenericPersistenceItem> items = repository.FindAll();
            Assert.AreEqual(3, items.Count);
            repository.Flush();
        }
    }

    [Test]
    public void CanDelete()
    {
        int itemID = SaveAnItem("k", null);

        using (repository)
        {
            GenericPersistenceItem item = repository.Get(itemID);
            Assert.IsNotNull(item, "There should be a saved item.");
            repository.Delete(item);
            repository.Flush();
        }

        using (repository)
        {
            GenericPersistenceItem item = repository.Get(itemID);
            Assert.IsNull(item, "Item is supposed to be deleted");
            repository.Flush();
        }
    }

    [Test]
    public void CanFindGreaterThanID()
    {
        int item1ID = SaveAnItem("first", null);
        int item2ID = SaveAnItem("second", null);
        int item3ID = SaveAnItem("third", null);

        using (repository)
        {
            ICollection<GenericPersistenceItem> items = repository.FindAll(NHibernate.Criterion.Expression.Gt("ID", 1));
            Assert.AreEqual(2, items.Count);
            repository.Flush();
        }
    }

    [Test]
    public void CanSaveDetail()
    {
        IRepository<int, ContentDetail> detailRepository = new NHRepository<int, ContentDetail>(sessionProvider);

        using (repository)
        {
            GenericPersistenceItem item = CreateOneItem<Definitions.PersistableItem1>(0, "item", null);
            item["TheString"] = "the string";
            repository.Save(item);
            repository.Flush();
        }

        using (detailRepository)
        {
            Assert.AreEqual(1, detailRepository.Count());
        }
    }

    [Test]
    public void CanDeleteDetail()
    {
        IRepository<int, ContentDetail> detailRepository = new NHRepository<int, ContentDetail>(sessionProvider);

        using (repository)
        {
            GenericPersistenceItem item = CreateOneItem<Definitions.PersistableItem1>(0, "item", null);
            item["TheString"] = "the string";
            repository.Save(item);
            repository.Flush();

            Assert.AreEqual(1, detailRepository.Count());

            item["TheString"] = null;
            repository.Save(item);
            repository.Flush();

            Assert.AreEqual(0, detailRepository.Count());
        }
    }

    [Test]
    public void DeleteItemCascadesDetails()
    {
        IRepository<int, ContentDetail> detailRepository = new NHRepository<int, ContentDetail>(sessionProvider);
        int itemID = 0;

        using (repository)
        {
            GenericPersistenceItem item = CreateOneItem<PersistableItem1>(0, "item", null);
            item["TheString"] = "the string";
            repository.Save(item);
            repository.Flush();
            itemID = item.ID;
        }
        using (detailRepository)
        {
            Assert.AreEqual(1, detailRepository.Count());
        }
        using (repository)
        {
            GenericPersistenceItem item = repository.Get(itemID);
            repository.Delete(item);
            repository.Flush();
        }
        using (detailRepository)
        {
            Assert.AreEqual(0, detailRepository.Count());
        }
    }

    [Test]
    public void ItemClasses_MayHaveNonVirtualProperties()
    {
        using (repository)
        {
            GenericPersistenceItem item = CreateOneItem<NonVirtualItem>(0, "item", null);
            repository.Save(item);
            repository.Flush();

            repository.Delete(item);
            repository.Flush();
        }
    }

    [Test]
    public void ItemClasses_MayHaveNonVirtualProperties_LazyLoading()
    {
        NonVirtualItem item;
        NonVirtualItem item2;
        NonVirtualItem item3;
        NonVirtualItem item4;
        NonVirtualItem item5;
        using (repository)
        {
            item = CreateOneItem<NonVirtualItem>(0, "item", null);
            item2 = CreateOneItem<NonVirtualItem>(0, "item2", item);
            item3 = CreateOneItem<NonVirtualItem>(0, "item3", item2);
            item4 = CreateOneItem<NonVirtualItem>(0, "item4", item3);
            item5 = CreateOneItem<NonVirtualItem>(0, "item5", item4);

            item.IntProperty = 1;
            item2.IntProperty = 2;
            item3.IntProperty = 3;
            item4.IntProperty = 4;
            item5.IntProperty = 5;

            repository.Save(item);
            repository.Flush();
        }

        using (repository)
        {
            Debug.WriteLine("A");

            Debug.WriteLine("one");
            item = repository.Get<NonVirtualItem>(item.ID);
            Debug.WriteLine("one.2");
            Assert.That(item.Name, Is.EqualTo("item"));
            Debug.WriteLine("one.3");
            Assert.That(item["IntProperty"], Is.EqualTo(1));

            Debug.WriteLine("two");
            Assert.That(item.Children.Count, Is.EqualTo(1));
            Debug.WriteLine("two.2");
            Assert.That(((GenericPersistenceItem)item.Children[0]).Name, Is.EqualTo("item2"));
            Debug.WriteLine("two.3");
            Assert.That(((GenericPersistenceItem)item.Children[0])["IntProperty"], Is.EqualTo(2));

            Debug.WriteLine("three");
            Assert.That(item.Children[0].Children.Count, Is.EqualTo(1));
            Debug.WriteLine("three.2");
            Assert.That(((GenericPersistenceItem)item.Children[0].Children[0]).Name, Is.EqualTo("item3"));
            Debug.WriteLine("three.3");
            Assert.That(((GenericPersistenceItem)item.Children[0].Children[0])["IntProperty"], Is.EqualTo(3));

            Debug.WriteLine("four");
            Assert.That(item.Children[0].Children[0].Children.Count, Is.EqualTo(1));
            Debug.WriteLine("four.2");
            Assert.That(((GenericPersistenceItem)item.Children[0].Children[0].Children[0]).Name, Is.EqualTo("item4"));
            Debug.WriteLine("four.3");
            Assert.That(((GenericPersistenceItem)item.Children[0].Children[0].Children[0])["IntProperty"], Is.EqualTo(4));

            Debug.WriteLine("five");
            Assert.That(item.Children[0].Children[0].Children[0].Children.Count, Is.EqualTo(1));
            Debug.WriteLine("four.2");
            Assert.That(((GenericPersistenceItem)item.Children[0].Children[0].Children[0].Children[0]).Name, Is.EqualTo("item5"));
            Debug.WriteLine("four.3");
            Assert.That(((GenericPersistenceItem)item.Children[0].Children[0].Children[0].Children[0])["IntProperty"], Is.EqualTo(5));
        }

        using (repository)
        {
            Debug.WriteLine("B");
            item4 = repository.Get<NonVirtualItem>(item4.ID);
            item = repository.Get<NonVirtualItem>(item.ID);
            item.LinkProperty = item4;
            repository.Save(item);
            repository.Flush();
        }

        using (repository)
        {
            Debug.WriteLine("C");
            item = repository.Get<NonVirtualItem>(item.ID);
            Assert.That(item.IntProperty, Is.EqualTo(1));
            Assert.That(item.LinkProperty, Is.EqualTo(item4));
            Assert.That(item.LinkProperty.Parent, Is.EqualTo(item3));
        }

        using (repository)
        {
            Debug.WriteLine("deleting");
            repository.Delete(repository.Get(item.ID));
            repository.Flush();
        }
    }

    private int SaveAnItem(string name, GenericPersistenceItem parent)
    {
        try
        {
            using (repository)
            {
                GenericPersistenceItem item = CreateOneItem<Definitions.PersistableItem1>(0, name, parent);
                repository.Save(item);
                repository.Flush();
                return item.ID;
            }
        }
        catch (Exception)
        {
            return 0;
        }

        
    }


}
}